/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * File Name          : freertos.c
 * Description        : Code for freertos applications
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "queue.h"
#include <stdio.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
uint16_t curScreenX = 240;
uint16_t curScreenY = 500;
uint16_t lastScreenX = 240;
uint16_t lastScreenY = 500;
/* USER CODE END Variables */
/* Definitions for Task_Draw */
osThreadId_t Task_DrawHandle;
const osThreadAttr_t Task_Draw_attributes = {
  .name = "Task_Draw",
  .stack_size = 256 * 4,
  .priority = (osPriority_t) osPriorityBelowNormal,
};
/* Definitions for Task_ScanKeys */
osThreadId_t Task_ScanKeysHandle;
const osThreadAttr_t Task_ScanKeys_attributes = {
  .name = "Task_ScanKeys",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for Queue_Keys */
osMessageQueueId_t Queue_KeysHandle;
const osMessageQueueAttr_t Queue_Keys_attributes = {
  .name = "Queue_Keys"
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void AppTask_Draw(void *argument);
void AppTask_ScanKeys(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
	/* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
	/* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
	/* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* Create the queue(s) */
  /* creation of Queue_Keys */
  Queue_KeysHandle = osMessageQueueNew (10, sizeof(uint8_t), &Queue_Keys_attributes);

  /* USER CODE BEGIN RTOS_QUEUES */
	/* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of Task_Draw */
  Task_DrawHandle = osThreadNew(AppTask_Draw, NULL, &Task_Draw_attributes);

  /* creation of Task_ScanKeys */
  Task_ScanKeysHandle = osThreadNew(AppTask_ScanKeys, NULL, &Task_ScanKeys_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
	/* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
	/* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_AppTask_Draw */
/**
 * @brief  Function implementing the Task_Draw thread.
 * @param  argument: Not used
 * @retval None
 */
/* USER CODE END Header_AppTask_Draw */
void AppTask_Draw(void *argument)
{
  /* USER CODE BEGIN AppTask_Draw */
	uint8_t queueName[30];
	sprintf(queueName, "Queue Name = %s", pcQueueGetName(Queue_KeysHandle));
	lcd_show_str(10, 40, 24, queueName, RED);

	uint8_t queueSizeString[30];
	sprintf(queueSizeString, "Queue size = %d", uxQueueSpacesAvailable(Queue_KeysHandle));
	lcd_show_str(10, 70, 24, queueSizeString, RED);
	KEYS keyValue;
	/* Infinite loop */
	for (;;) {
		uint8_t tempStr[30];
		sprintf(tempStr, "uxQueueMessagesWaiting() = %d   ", uxQueueMessagesWaiting(Queue_KeysHandle));
		lcd_show_str(10, 100, 24, tempStr, RED);

		sprintf(tempStr, "uxQueueSpacesAvailable() = %d   ", uxQueueSpacesAvailable(Queue_KeysHandle));
		lcd_show_str(10, 130, 24, tempStr, RED);

		sprintf(tempStr, "Task_Draw HighWaterMark = %d", uxTaskGetStackHighWaterMark(Task_DrawHandle));
		lcd_show_str(10, 160, 24, tempStr, RED);

		sprintf(tempStr, "Task_ScanKeys HighWaterMark = %d", uxTaskGetStackHighWaterMark(Task_ScanKeysHandle));
		lcd_show_str(10, 190, 24, tempStr, RED);

		if (xQueueReceive(Queue_KeysHandle, &keyValue, pdMS_TO_TICKS(50)) != pdTRUE) {
			continue;
		}

		if (keyValue == KEY_LEFT) {
			curScreenX -= 10;
		} else if (keyValue == KEY_RIGHT) {
			curScreenX += 10;
		} else if (keyValue == KEY_DOWN) {
			curScreenY += 10;
		} else if (keyValue == KEY_UP) {
			curScreenY -= 10;
		}

		if (curScreenX > lcddev.width) {
			curScreenX = lcddev.width;
		}
		if (curScreenY > lcddev.height) {
			curScreenY = lcddev.height;
		}

		lcd_draw_line(lastScreenX, lastScreenY, curScreenX, curScreenY, BLACK);

		lastScreenX = curScreenX;
		lastScreenY = curScreenY;

		vTaskDelay(pdMS_TO_TICKS(400));
	}
  /* USER CODE END AppTask_Draw */
}

/* USER CODE BEGIN Header_AppTask_ScanKeys */
/**
 * @brief Function implementing the Task_ScanKeys thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_AppTask_ScanKeys */
void AppTask_ScanKeys(void *argument)
{
  /* USER CODE BEGIN AppTask_ScanKeys */
	GPIO_PinState keyState = GPIO_PIN_SET;
//	KEYS key = KEY_NONE;
	uint8_t key = KEY_NONE;
	/* Infinite loop */
	for (;;) {
		key = KEY_NONE;

		keyState = HAL_GPIO_ReadPin(KeyLeft_GPIO_Port, KeyLeft_Pin);
		if (keyState == GPIO_PIN_RESET) {
			key = KEY_LEFT;
		}

		keyState = HAL_GPIO_ReadPin(KeyRight_GPIO_Port, KeyRight_Pin);
		if (keyState == GPIO_PIN_RESET) {
			key = KEY_RIGHT;
		}

		keyState = HAL_GPIO_ReadPin(KeyUp_GPIO_Port, KeyUp_Pin);
		if (keyState == GPIO_PIN_SET) {
			key = KEY_UP;
		}

		keyState = HAL_GPIO_ReadPin(KeyDown_GPIO_Port, KeyDown_Pin);
		if (keyState == GPIO_PIN_RESET) {
			key = KEY_DOWN;
		}

		if (key != KEY_NONE) {
			BaseType_t err = xQueueSendToBack(Queue_KeysHandle, &key, pdMS_TO_TICKS(50));
			if (err == errQUEUE_FULL) {
				xQueueReset(Queue_KeysHandle);
			}
			vTaskDelay(pdMS_TO_TICKS(300));
		} else {
			vTaskDelay(pdMS_TO_TICKS(5));
		}
	}
  /* USER CODE END AppTask_ScanKeys */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

